﻿using JT809.GpsRedisConsumer.Models;
using log4net;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Quartz;
using SqlSugar;
using SqlSugar.IOC;

namespace JT809.GpsRedisConsumer
{
    [PersistJobDataAfterExecution]
    [DisallowConcurrentExecution]
    public class JobDetail : IJob
    {
        private readonly IConfiguration _configuration;
        private readonly ILog _logger;

        //public const string startKey = "startKey";
        private readonly static DateTime dnt = DateTime.Now;

        public JobDetail(IConfiguration configuration)
        {
            _configuration = configuration;
            _logger = LogManager.GetLogger(LogHelper.Repository.Name, GetType().Name);
        }
        public async Task Execute(IJobExecutionContext context)
        {
            try
            {
                JobDataMap data = context.JobDetail.JobDataMap;
                JobKey jobKey = context.JobDetail.Key;
                //bool _startKey = data.GetBoolean(startKey);
                //data.Put(startKey, false);
                _logger.Debug($"【{jobKey}】 executing at {DateTime.Now.ToString("yyyy年MM月dd HH时mm分ss秒")}");

                bool.TryParse(_configuration.GetSection("Redis:Enabled").Value, out var redisEnabled);
                if (!redisEnabled)
                {
                    throw new Exception("未开启redis,当前执行无效定时任务");
                }

                try
                {
                    var _saveTogpsInfo = bool.TryParse(_configuration.GetSection("DataBase:SaveTogpsInfo").Value, out var SaveTogpsInfo) ? SaveTogpsInfo : true;
                    var _saveTogpsInfoPro = bool.TryParse(_configuration.GetSection("DataBase:SaveTogpsInfoPro").Value, out var SaveTogpsInfoPro) ? SaveTogpsInfoPro : true;
                    //测试分表代码
                    //var datas = new List<GpsPosition>()
                    //{
                    //    new GpsPosition(){CreateTime=Convert.ToDateTime("2019-12-1")} ,
                    //    new GpsPosition(){CreateTime=Convert.ToDateTime("2022-02-1")},
                    //    new GpsPosition(){CreateTime=Convert.ToDateTime("2020-02-1")},
                    //    new GpsPosition(){CreateTime=Convert.ToDateTime("2021-12-1")}
                    //};
                    //DbScoped.SugarScope.Insertable(datas).SplitTable().ExecuteReturnSnowflakeIdList();//插入返回雪花ID集合

                    //var rkey = $"List:{DateTime.Now.ToString("yyMMdd")}:0x1202";
                    var rkey = $"List:0x1202";
                    var len = RedisHelper.LLen(rkey) >= 50000 ? 49999 : -1;
                    var list_GpsPositions = await RedisHelper.LRangeAsync<string>(rkey, 0, len);
                    int listCount = list_GpsPositions.Count();

                    if ((_configuration.GetSection("Region")?.Value ?? "").ToLower() == "haining")
                    {
                        List<GpsInfoPro> gpsInfoPros = new List<GpsInfoPro>();
                        List<GpsInfoHN> gpsInfos = new List<GpsInfoHN>();

                        var pipe = RedisHelper.StartPipe();

                        foreach (var item in list_GpsPositions)
                        {
                            GpsInfoPro gpsPosition = JsonConvert.DeserializeObject<GpsInfoPro>(item);
                            if (listCount >= 1000)
                            {
                                ////大数据写入，雪花Id
                                gpsPosition.Id = SnowFlakeSingle.Instance.NextId(); //目前需要实体手动赋值
                            }

                            if (_saveTogpsInfoPro)
                            {
                                gpsInfoPros.Add(gpsPosition);
                            }

                            if (_saveTogpsInfo)
                            {
                                //避免将历史轨迹数据插入到历史分表中（即2023年10月12日之前的数据）。历史分表中因为有数据，所以导致新的分表方法无法修改数据表结构，会导致报错。此处判断过滤到以前老坐标点
                                if (DateTime.Compare(gpsPosition.GpsTime2, DateTime.Parse("2023-10-12")) >= 0)
                                {
                                    gpsInfos.Add(new GpsInfoHN
                                    {
                                        gpsId = gpsPosition.Id,
                                        SendTime = gpsPosition.GpsTime2,
                                        Latitude = gpsPosition.Lat2,
                                        Longitude = gpsPosition.Lon2,
                                        Altitude = gpsPosition.Altitude,
                                        Direction = gpsPosition.Direction,
                                        Mileage = gpsPosition.Vec3,
                                        Velocity = gpsPosition.Vec1,
                                        RecordVelocity = gpsPosition.Vec2,
                                        AlarmState = gpsPosition.Alarm,
                                        Status = gpsPosition.State,
                                        PlateNo = gpsPosition.Vno
                                    });
                                }
                            }

                            #region 保存在线的车辆信息
                            //车辆状态详细信息保存5分钟
                            pipe.Set($"String:OnlineCarVno:{gpsPosition.Vno}", JsonConvert.SerializeObject(new GPSRealData
                            {
                                Status = gpsPosition.State2,
                                AlarmState = gpsPosition.Alarm2,
                                PlateNo = gpsPosition.Vno,
                                SendTime = gpsPosition.GpsTime2,
                                UpdateDate = DateTime.Now,
                                Longitude = (decimal)gpsPosition.Lon2,
                                Latitude = (decimal)gpsPosition.Lat2,
                                Velocity = gpsPosition.Vec1,
                                Direction = gpsPosition.Direction,
                                Altitude = gpsPosition.Altitude,
                                Mileage = gpsPosition.Vec3,
                                Valid = gpsPosition.State2.Substring(30, 1) == "1",
                                Online = true
                            }), 300);

                            #endregion
                        }
                        pipe.EndPipe();

                        if (listCount > 0)
                        {
                            if (listCount >= 1000)
                            {
                                //大数据写入
                                if (_saveTogpsInfoPro)
                                {
                                    var Result = DbScoped.SugarScope.Fastest<GpsInfoPro>().SplitTable().BulkCopy(gpsInfoPros);//自动找表大数据写入
                                    _logger.Info($"【大数据插入GpsInfoPro】【{rkey}中有[{Result}]条数据成功插入到数据库中】");
                                }

                                if (_saveTogpsInfo)
                                {
                                    var ResultGps = DbScoped.SugarScope.Fastest<GpsInfoHN>().SplitTable().BulkCopy(gpsInfos);//自动找表大数据写入
                                    _logger.Info($"【大数据插入GpsInfo】【{rkey}中有[{ResultGps}]条数据成功插入到数据库中】");
                                }
                            }
                            else
                            {
                                if (_saveTogpsInfoPro)
                                {
                                    //常规插入
                                    var IdList = await DbScoped.SugarScope.Insertable(gpsInfoPros).SplitTable().ExecuteReturnSnowflakeIdListAsync();
                                    _logger.Info($"【常规插入GpsInfoPro】【{rkey}中有[{IdList.Count}]条数据成功插入到数据库中】");
                                }

                                if (_saveTogpsInfo)
                                {
                                    var gpsInfosist = await DbScoped.SugarScope.Insertable(gpsInfos).SplitTable().ExecuteReturnSnowflakeIdListAsync();
                                    _logger.Info($"【常规插入GpsInfo】【{rkey}中有[{gpsInfosist.Count}]条数据成功插入到数据库中】");
                                }
                            }
                            RedisHelper.LTrim(rkey, listCount, -1);
                        }

                        //读出数据库中所有车辆记录
                        var listGpsRealData = await DbScoped.SugarScope.GetConnection("sql2").Queryable<GPSRealData>().ToListAsync();

                        pipe.Del("SortedSet:DatabaseFreshedVno");
                        //数据库中所有数据与在线数据比较，刷新数据库中所有数据状态
                        for (int i = 0; i < listGpsRealData.Count; i++)
                        {
                            //查询当前车牌是否在在线
                            var online = RedisHelper.Get<GPSRealData>($"String:OnlineCarVno:{listGpsRealData[i].PlateNo}");
                            if (online != null)
                            {
                                online.Id = listGpsRealData[i].Id;
                                listGpsRealData[i] = online;
                                //将数库中车辆数据与在线车辆已经对比中的车牌信息记录到集合DatabaseFreshedVno中
                                pipe.SAdd("SortedSet:DatabaseFreshedVno", listGpsRealData[i].PlateNo);
                            }
                            else
                            {
                                listGpsRealData[i].Online = false;
                            }
                        }
                        pipe.EndPipe();

                        //读出Redis中所有在线车辆记录
                        var listRedisCar = (await RedisHelper.KeysAsync("jt809:String:OnlineCarVno:*")).ToList();
                        if (RedisHelper.Exists("SortedSet:DatabaseFreshedVno"))
                        {
                            #region 把在线车辆跟数据库中已匹配过的车辆数据剔除，把在线车辆剔除剩下的没有跟数据库中匹配的车辆数据插入到数据库中
                            //取出当前所有在线车辆车牌，存到集合AllOnlineVno中
                            pipe.Del("SortedSet:AllOnlineVno");
                            foreach (var key in listRedisCar)
                            {
                                var keyOnlyLast = key.Substring(key.LastIndexOf(":") + 1);
                                pipe.SAdd("SortedSet:AllOnlineVno", keyOnlyLast);
                            }
                            pipe.EndPipe();

                            //将所有在线车辆集合AllOnlineVno与跟数据库已对比车牌集合DatabaseFreshedVno，进行差集操作，将差值追加到listGpsRealData列表中
                            var sdiffList = (await RedisHelper.SDiffAsync("SortedSet:AllOnlineVno", "SortedSet:DatabaseFreshedVno")).ToList();
                            foreach (var key in sdiffList)
                            {
                                var keyOnlie = $"String:OnlineCarVno:{key}";
                                var gPSRealData = RedisHelper.Get(keyOnlie);
                                listGpsRealData.Add(JsonConvert.DeserializeObject<GPSRealData>(gPSRealData));
                            }

                            //操作完成，清除两个集合数据
                            pipe.Del("SortedSet:AllOnlineVno");
                            pipe.Del("SortedSet:DatabaseFreshedVno");
                            pipe.EndPipe();
                            #endregion
                        }
                        else
                        {
                            #region 当在线车辆跟数库中所有车辆数据都跟都不匹配时，把这些在线车辆全部插入到数据库中
                            foreach (var key in listRedisCar)
                            {
                                var keyWithoutprefix = key.Substring(key.IndexOf(":") + 1);
                                var realData = RedisHelper.Get(keyWithoutprefix);
                                listGpsRealData.Add(JsonConvert.DeserializeObject<GPSRealData>(realData));
                            }
                            #endregion
                        }

                        _logger.Debug($"待更新数据库的数据共【{listGpsRealData.Count()}】条");

                        int storeCount = 0;
                        string errObject = "";
                        try
                        {
                            foreach (var item in listGpsRealData)
                            {
                                errObject = JsonConvert.SerializeObject(item);
                                int sCount = await DbScoped.SugarScope.GetConnection("sql2").Storageable(item).ExecuteCommandAsync();
                                storeCount += sCount;
                            }
                        }
                        catch
                        {
                            _logger.Info($"当前待刷新失败的数据【{errObject}】");
                            throw;
                        }

                        _logger.Info($"当前轮训刷新数据库车辆共【{storeCount}】辆");
                    }
                    else
                    {
                        List<GpsInfoPro> gpsInfoPros = new List<GpsInfoPro>();
                        List<GpsInfo> gpsInfos = new List<GpsInfo>();

                        var pipe = RedisHelper.StartPipe();

                        foreach (var item in list_GpsPositions)
                        {
                            GpsInfoPro gpsPosition = JsonConvert.DeserializeObject<GpsInfoPro>(item);
                            if (listCount >= 1000)
                            {
                                ////大数据写入，雪花Id
                                gpsPosition.Id = SnowFlakeSingle.Instance.NextId(); //目前需要实体手动赋值
                            }

                            if (_saveTogpsInfoPro)
                            {
                                gpsInfoPros.Add(gpsPosition);
                            }

                            if (_saveTogpsInfo)
                            {
                                gpsInfos.Add(new GpsInfo
                                {
                                    gpsId = gpsPosition.Id,
                                    SendTime = gpsPosition.GpsTime2,
                                    Latitude = gpsPosition.Lat2,
                                    Longitude = gpsPosition.Lon2,
                                    Altitude = gpsPosition.Altitude,
                                    Direction = gpsPosition.Direction,
                                    Mileage = gpsPosition.Vec3,
                                    Velocity = gpsPosition.Vec1,
                                    RecordVelocity = gpsPosition.Vec2,
                                    AlarmState = gpsPosition.Alarm2,
                                    Status = gpsPosition.State2,
                                    PlateNo = gpsPosition.Vno
                                });
                            }

                            #region 保存在线的车辆信息，车辆状态详细信息保存5分钟
                            if ((gpsPosition.State & (int)VehicleState.ACCOpen) == (int)VehicleState.ACCOpen)
                            {
                                //ACC开的车辆，即在线的车辆，保留5分钟
                                pipe.Set($"String:ACCOpenCarVno:{gpsPosition.Vno}", JsonConvert.SerializeObject(new GPSRealData
                                {
                                    Status = gpsPosition.State2,
                                    AlarmState = gpsPosition.Alarm2,
                                    PlateNo = gpsPosition.Vno,
                                    SendTime = gpsPosition.GpsTime2,
                                    UpdateDate = DateTime.Now,
                                    Longitude = (decimal)gpsPosition.Lon2,
                                    Latitude = (decimal)gpsPosition.Lat2,
                                    Velocity = gpsPosition.Vec1,
                                    Direction = gpsPosition.Direction,
                                    Altitude = gpsPosition.Altitude,
                                    Mileage = gpsPosition.Vec3,
                                    Valid = (gpsPosition.State & (int)VehicleState.Location) == (int)VehicleState.Location,  //gpsPosition.State2.Substring(30, 1) == "1",
                                    Online = true//VehicleState.ACCOpen
                                }), 300);
                            }
                            else
                            {
                                //ACC关的车辆，即离线的车辆
                                pipe.Set($"String:LocationCarVno:{gpsPosition.Vno}", JsonConvert.SerializeObject(new GPSRealData
                                {
                                    Status = gpsPosition.State2,
                                    AlarmState = gpsPosition.Alarm2,
                                    PlateNo = gpsPosition.Vno,
                                    SendTime = gpsPosition.GpsTime2,
                                    UpdateDate = DateTime.Now,
                                    Longitude = (decimal)gpsPosition.Lon2,
                                    Latitude = (decimal)gpsPosition.Lat2,
                                    Velocity = gpsPosition.Vec1,
                                    Direction = gpsPosition.Direction,
                                    Altitude = gpsPosition.Altitude,
                                    Mileage = gpsPosition.Vec3,
                                    Valid = (gpsPosition.State & (int)VehicleState.Location) == (int)VehicleState.Location,  //gpsPosition.State2.Substring(30, 1) == "1",
                                    Online = false//VehicleState.ACCOpen
                                }), 300);
                            }
                            #endregion
                        }
                        pipe.EndPipe();

                        if (listCount > 0)
                        {
                            if (listCount >= 1000)
                            {
                                //大数据写入
                                if (_saveTogpsInfoPro)
                                {
                                    var Result = DbScoped.SugarScope.Fastest<GpsInfoPro>().SplitTable().BulkCopy(gpsInfoPros);//自动找表大数据写入
                                    _logger.Info($"【大数据插入GpsInfoPro】【{rkey}中有[{Result}]条数据成功插入到数据库中】");
                                }

                                if (_saveTogpsInfo)
                                {
                                    var ResultGps = DbScoped.SugarScope.Fastest<GpsInfo>().SplitTable().BulkCopy(gpsInfos);//自动找表大数据写入
                                    _logger.Info($"【大数据插入GpsInfo】【{rkey}中有[{ResultGps}]条数据成功插入到数据库中】");
                                }
                            }
                            else
                            {
                                if (_saveTogpsInfoPro)
                                {
                                    //常规插入
                                    var IdList = await DbScoped.SugarScope.Insertable(gpsInfoPros).SplitTable().ExecuteReturnSnowflakeIdListAsync();
                                    _logger.Info($"【常规插入GpsInfoPro】【{rkey}中有[{IdList.Count}]条数据成功插入到数据库中】");
                                }

                                if (_saveTogpsInfo)
                                {
                                    var gpsInfosist = await DbScoped.SugarScope.Insertable(gpsInfos).SplitTable().ExecuteReturnSnowflakeIdListAsync();
                                    _logger.Info($"【常规插入GpsInfo】【{rkey}中有[{gpsInfosist.Count}]条数据成功插入到数据库中】");
                                }
                            }
                            RedisHelper.LTrim(rkey, listCount, -1);
                        }

                        //读出数据库中所有车辆记录
                        var listGpsRealData = await DbScoped.SugarScope.GetConnection("sql2").Queryable<GPSRealData>().ToListAsync();

                        pipe.Del("SortedSet:DatabaseFreshedVno");
                        //数据库中所有数据与在线数据比较，刷新数据库中所有数据状态
                        for (int i = 0; i < listGpsRealData.Count; i++)
                        {
                            //查询当前车牌是否在在线
                            var online = RedisHelper.Get<GPSRealData>($"String:ACCOpenCarVno:{listGpsRealData[i].PlateNo}");
                            if (online != null)
                            {
                                online.Id = listGpsRealData[i].Id;
                                listGpsRealData[i] = online;
                                //将数库中车辆数据与在线车辆已经对比中的车牌信息记录到集合DatabaseFreshedVno中
                                pipe.SAdd("SortedSet:DatabaseFreshedVno", listGpsRealData[i].PlateNo);
                            }
                            else
                            {
                                listGpsRealData[i].Online = false;
                            }
                        }
                        pipe.EndPipe();

                        //读出Redis中所有在线车辆记录
                        var listRedisCar = (await RedisHelper.KeysAsync("jt809:String:ACCOpenCarVno:*")).ToList();
                        if (RedisHelper.Exists("SortedSet:DatabaseFreshedVno"))
                        {
                            #region 把在线车辆跟数据库中已匹配过的车辆数据剔除，把在线车辆剔除剩下的没有跟数据库中匹配的车辆数据插入到数据库中
                            //取出当前所有在线车辆车牌，存到集合AllOnlineVno中
                            pipe.Del("SortedSet:AllOnlineVno");
                            foreach (var key in listRedisCar)
                            {
                                var keyOnlyLast = key.Substring(key.LastIndexOf(":") + 1);
                                pipe.SAdd("SortedSet:AllOnlineVno", keyOnlyLast);
                            }
                            pipe.EndPipe();

                            //将所有在线车辆集合AllOnlineVno与跟数据库已对比车牌集合DatabaseFreshedVno，进行差集操作，将差值追加到listGpsRealData列表中
                            var sdiffList = (await RedisHelper.SDiffAsync("SortedSet:AllOnlineVno", "SortedSet:DatabaseFreshedVno")).ToList();
                            foreach (var key in sdiffList)
                            {
                                var keyOnlie = $"String:ACCOpenCarVno:{key}";
                                var gPSRealData = RedisHelper.Get(keyOnlie);
                                listGpsRealData.Add(JsonConvert.DeserializeObject<GPSRealData>(gPSRealData));
                            }

                            //操作完成，清除两个集合数据
                            pipe.Del("SortedSet:AllOnlineVno");
                            pipe.Del("SortedSet:DatabaseFreshedVno");
                            pipe.EndPipe();
                            #endregion
                        }
                        else
                        {
                            #region 当在线车辆跟数库中所有车辆数据都跟都不匹配时，把这些在线车辆全部插入到数据库中
                            foreach (var key in listRedisCar)
                            {
                                var keyWithoutprefix = key.Substring(key.IndexOf(":") + 1);
                                var realData = RedisHelper.Get(keyWithoutprefix);
                                listGpsRealData.Add(JsonConvert.DeserializeObject<GPSRealData>(realData));
                            }
                            #endregion
                        }

                        var storeCount = await DbScoped.SugarScope.GetConnection("sql2").Storageable(listGpsRealData).ExecuteCommandAsync();
                        _logger.Info($"当前轮训刷新数据库车辆共{storeCount}辆");
                    }
                }
                catch (Exception eex)
                {
                    _logger.Info($"【JobDetail,List:0x1202】{eex.Message}");
                    _logger.Debug(eex);
                }

            }
            catch (Exception ex)
            {
                _logger.Info(ex.Message);
                _logger.Debug(ex);
            }
        }
    }
}
